package com.inspur.edp.web.relycheck.dependencyvalidator;

import com.inspur.edp.formserver.viewmodel.GspViewModel;
import com.inspur.edp.formserver.viewmodel.GspViewModelElement;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.spi.MetadataElementValidator;
import com.inspur.edp.lcm.metadata.spi.entity.MetadataElement;
import com.inspur.edp.lcm.metadata.spi.entity.ValidateResult;
import com.inspur.edp.web.common.customexception.WebCustomException;
import com.inspur.edp.web.common.utility.StringUtility;
import com.inspur.edp.web.relycheck.constant.RelyCheckType;
import com.inspur.edp.web.relycheck.constant.ValidateConstants;
import com.inspur.edp.web.relycheck.dependencygenerator.entity.SourceElementField;
import com.inspur.edp.web.relycheck.dependencyvalidator.element.*;
import com.inspur.edp.web.relycheck.utility.StringConcatUtility;
import com.inspur.edp.web.relycheck.utility.ValidateResultUtility;

import javax.annotation.Resource;

/**
 * VoElement 依赖检查
 *
 * @author noah
 */
public class VoElementValidator extends AbstractDependencyValidator implements MetadataElementValidator {
    @Resource
    private RequireValidator requireValidator;

    @Resource
    private MultiLanguageValidator multiLanguageValidator;

    @Resource
    private LengthValidator lengthValidator;

    @Resource
    private PrecisionValidator precisionValidator;

    @Resource
    private DataTypeValidator dataTypeValidator;

    @Resource
    private EnumValueValidator enumValueValidator;

    @Override
    public String getReferenceType() {
        return RelyCheckType.SchemaField.getReferenceType();
    }

    @Override
    public ValidateResult validate(MetadataElement sourceMetadataElement, MetadataElement targetMetadataElement, GspMetadata sourceGspMetadata, GspMetadata targetGspMetadata) {
        if (targetGspMetadata == null) {
            // 如果VO元数据不存在  从VOEntity中进行校验 不在此处校验
            return ValidateResultUtility.success();
        }

        // 目标元数据必须为VO元数据
        if (!(targetGspMetadata.getContent() instanceof GspViewModel)) {
            throw new WebCustomException("表单元数据字段校验，目标类型必须为GspViewModel,当前为：" + targetGspMetadata.getContent().getClass().getName());
        }

        ValidateResult warningValidateResult = ValidateResultUtility.success();
        if (sourceMetadataElement.getType().equals(RelyCheckType.SchemaField.getType()) &&
                targetMetadataElement.getType().equals(RelyCheckType.SchemaField.getReferenceType())) {
            SourceElementField field = (SourceElementField) sourceMetadataElement.getContent();
            GspViewModelElement gspViewModelElement = (GspViewModelElement) targetMetadataElement.getContent();
            // 新增字段不关心 放在实体校验中进行warning 提示

            String voMetadataName = targetGspMetadata.getHeader().getName();
            String formMetadataName = sourceGspMetadata.getHeader().getName();
            String entityCode = field.getSourceEntity().getCode();

            ElementValidateParameter validateParameter = new ElementValidateParameter() {
                {
                    this.setFormMetadata(sourceGspMetadata);
                    this.setSourceElementField(field);
                    this.setGspViewModelElement(gspViewModelElement);
                    this.setViewModelMetadata(targetGspMetadata);
                    this.setVoMetadataName(voMetadataName);
                    this.setFormMetadataName(formMetadataName);
                    this.setEntityCode(entityCode);
                }
            };


            // 1.删除字段 表中删除了字段
            if (gspViewModelElement == null) {
                return ValidateResultUtility.failureWithError(String.format("视图对象%1$s中子表%2$s删除了字段%3$s" + ValidateConstants.Comma + "请在表单%4$s的实体树中执行更新schema操作",
                        StringConcatUtility.concatWithNamePrefix(voMetadataName, true),
                        StringConcatUtility.concatWithCodePrefix(entityCode, true),
                        StringConcatUtility.concatWithCodePrefix(field.getSourceField().getCode(), true),
                        StringConcatUtility.concatWithNamePrefix(formMetadataName, true)));
            }
            // 2.修改字段 code，理论上 字段code是不允许更改
            if (!StringUtility.equals(field.getSourceField().getCode(), gspViewModelElement.getCode())) {
                return ValidateResultUtility.failureWithError(String.format("视图对象%1$s中子表%2$s的字段编号由%3$s更改为%4$s" + ValidateConstants.Comma + "请在表单%5$s的实体树中执行更新schema操作",
                        StringConcatUtility.concatWithNamePrefix(voMetadataName, true),
                        StringConcatUtility.concatWithCodePrefix(entityCode, true),
                        StringConcatUtility.concatWithCodePrefix(field.getSourceField().getCode(), true),
                        StringConcatUtility.concatWithCodePrefix(gspViewModelElement.getCode(), true),
                        StringConcatUtility.concatWithNamePrefix(formMetadataName, true)));
            }

            // 3.修改字段名称，表单不是必须需要调整，但可以依据新的字段名称进行调整 warning
            if (!StringUtility.equals(field.getSourceField().getName(), gspViewModelElement.getName())) {
                warningValidateResult = ValidateResultUtility.failureWithWarning(String.format("视图对象%1$s中子表%2$s的字段名称由%3$s更改为%4$s" + ValidateConstants.Comma + "请在表单%5$s的实体树种执行更新schema操作",
                        StringConcatUtility.concatWithNamePrefix(voMetadataName, true),
                        StringConcatUtility.concatWithCodePrefix(entityCode, true),
                        StringConcatUtility.concatWithCodePrefix(field.getSourceField().getCode(), true),
                        StringConcatUtility.concatWithNamePrefix(gspViewModelElement.getName(), true),
                        StringConcatUtility.concatWithNamePrefix(formMetadataName, true)
                ));
            }

            // 是否必填
            ValidateResult requireValidateResult = this.requireValidator.validate(validateParameter);
            if (ValidateResultUtility.canContinute(requireValidateResult)) {
                warningValidateResult = requireValidateResult;
            } else {
                return requireValidateResult;
            }


            // 是否多语
            ValidateResult multiLanguageValidateResult = this.multiLanguageValidator.validate(validateParameter);
            if (ValidateResultUtility.canContinute(multiLanguageValidateResult)) {
                warningValidateResult = multiLanguageValidateResult;
            } else {
                return multiLanguageValidateResult;
            }

            // 比较长度
            // 仅比较存在长度的字段参数
            ValidateResult lengthValidateResult = this.lengthValidator.validate(validateParameter);
            if (ValidateResultUtility.canContinute(lengthValidateResult)) {
                warningValidateResult = lengthValidateResult;
            } else {
                return lengthValidateResult;
            }

            // 比较精度
            ValidateResult precisionValidateResult = this.precisionValidator.validate(validateParameter);
            if (ValidateResultUtility.canContinute(precisionValidateResult)) {
                warningValidateResult = precisionValidateResult;
            } else {
                return precisionValidateResult;
            }


            // 比较数据类型
            ValidateResult checkDataTypeRelateResult = this.dataTypeValidator.validate(validateParameter);
            if (ValidateResultUtility.canContinute(checkDataTypeRelateResult)) {
                warningValidateResult = checkDataTypeRelateResult;
            } else {
                return checkDataTypeRelateResult;
            }

            // 比较枚举值  首先如果数据类型发生了变更，需要先检测数据类型发生了变化
            // 在检测枚举值是否发生变化时，可以认为类型一致 且均为枚举类型
            ValidateResult enumValueValidateResul = this.enumValueValidator.validate(validateParameter);
            if (ValidateResultUtility.canContinute(enumValueValidateResul)) {
                warningValidateResult = enumValueValidateResul;
            } else {
                return enumValueValidateResul;
            }

        }

        if (!warningValidateResult.isValid()) {
            return warningValidateResult;
        }
        return ValidateResultUtility.success();
    }

}
